#pragma once
#include <iostream>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
using namespace std;
const char *pathname = "/home";
const int proj_id = 0x12;
const int defaultsize = 4096;
// 获取key值
key_t GetShmKeyOrDie()
{
    key_t key = ftok(pathname, proj_id);
    if (key < 0)
    {
        cerr << "创建key失败,错误码为:" << errno << " 错误信息为:" << strerror(errno) << endl;
        exit(1);
    }
    return key;
}
// 将key值转换为十六进制
string ToHex(key_t key)
{
    char buffer[1024];
    snprintf(buffer, sizeof(buffer), "0x%x", key);
    return buffer;
}

// 创建共享内存
int CreatShmOrDie(key_t key, size_t size, int flag)
{
    int shmid = shmget(key, size, flag);
    if (shmid < 0)
    {
        cerr << "创建共享内存失败,错误码为:" << errno << " 错误信息为:" << strerror(errno) << endl;
        exit(2);
    }
    return shmid;
}

// 服务端创建共享内存
int Creatshm(key_t key, size_t size)
{
    // 服务端:一定要创建出一个新的共享内存
    return CreatShmOrDie(key, size, IPC_CREAT | IPC_EXCL);
}

// 客户端获取共享内存
int Getshm(key_t key, size_t size)
{
    // 服务端:获取已经创建好的共享内存即可
    return CreatShmOrDie(key, size, IPC_CREAT);
}

// 删除共享内存
void DeleteShm(int shmid)
{
    int n = shmctl(shmid, IPC_RMID, nullptr);
    if (n < 0)
    {
        cerr << "删除共享内存失败" << endl;
    }
    else
    {
        cout << "删除共享内存成功,shmid:" << shmid << endl;
    }
}

// 获取共享内存信息
void DebugPrint(int shmid)
{
    struct shmid_ds shms;
    int n = shmctl(shmid, IPC_STAT, &shms);
    if (n < 0)
    {
        cerr << "删除共享内存失败" << endl;
        return;
    }
    cout << "共享内存大小:" << shms.shm_segsz << endl;
    cout << "与此共享内存挂接的进程个数:" << shms.shm_nattch << endl;
    cout << "创建此共享内存的时间:" << shms.shm_ctime << endl;
    cout << "此共享内存的key值:" << ToHex(shms.shm_perm.__key) << endl;
}

// 挂接共享内存
void *shmAttach(int shmid)
{
    void *addr = shmat(shmid, nullptr, 0);
    if ((long long int)addr == -1)
    {
        cerr << "挂接共享内存失败" << endl;
        return nullptr;
    }
    return addr;
}

// 与此共享内存去关联
void ShmDetach(void *addr)
{
    int n = shmdt(addr);
    if (n < 0)
    {
        cerr << "去关联失败" << endl;
    }
}